from flask import Flask
from flask_siwadoc import SiwaDoc, ValidationError
from pydantic import BaseModel, Field, validator

app = Flask(__name__)

siwa = SiwaDoc(app)


class QueryModel(BaseModel):
    page: int = Field(default=1, title="current page number")
    size: int = Field(default=20, title="size of page", ge=10, le=100)
    keyword: str = Field(default="", title="search keyword")


@app.route("/users1", methods=["GET"])
@siwa.doc(query=QueryModel, tags=['user'])
def users1():
    """
    pydantic 属性校验
    """
    return [{"username": "siwa_pydantic", "id": 1}]


@app.route("/users2", methods=["GET"])
@siwa.doc(query=QueryModel, tags=["user"])
def users2(query: QueryModel):
    """
    example 2：指定查询参数 query
    :param query: QueryModel
    :return: str
    """
    print(query.keyword)
    return "hello"


@app.route("/users3", methods=["POST"])
@siwa.doc(body=QueryModel, tags=["user"])
def users3(query: QueryModel):
    """
    example3 :指定请求体 body
    :param query: QueryModel
    :return: query.json()
    """
    print(query.keyword)
    print(query.json())
    print(query.page)
    return query.json()


class LoginModel(BaseModel):
    """
    校验 用户名和密码 长度
    """
    username: str = Field(title="username", min_length=1, max_length=6)
    password: str = Field(min_length=1, max_length=6)

    @validator('username')
    def validate_username(cls, value):
        if not (1 <= len(value) <= 6):
            raise ValueError('Username must be between 1 and 6 characters long.')
        return value

    @validator('password')
    def validate_password(cls, value):
        if not (1 <= len(value) <= 6):
            raise ValueError('Password must be between 1 and 6 characters long.')
        return value

    @app.errorhandler(ValidationError)
    def validate_error(e: ValidationError):
        """
        这时候，我们可以通过使用flask的 errorhandler() 装饰函数来注册ValidationError错误，
        异常就可以被validate_error函数捕获，开发者可以给前端直接返回一个友好的错误响应体
        :return: error entry
        """
        return dict(code=-1, msg="请求参数错误", error_info=e.errors()), 400


@app.route("/login", methods=["POST"])
@siwa.doc(body=LoginModel, tags=['login'])
def login(body: LoginModel):
    """
    example3 :指定请求体 body
    :param body: LoginModel
    :return: dict
    """
    return {"username": body.username, "id": 1}


@app.route('/')
@siwa.doc(tags=["hello"], description="hello world")
def hello_world():  # put application's code here
    return 'Hello World!'


class UserModel(BaseModel):
    id: int
    username: str


@app.route("/users/1", methods=["GET"])
@siwa.doc(tags=["user"], resp=UserModel)
def users4():
    """
    example4: 指定返回体 resp
    """
    return {"username": "siwa_pydantic"}


class QueryModel(BaseModel):
    gender: str
    @validator('gender')
    def validate_username(cls, value):
        if not (1 <= len(value) <= 6):
            raise ValueError('gender must be between 1 and 6 characters long.')
        return value


class UserModel(BaseModel):
    """
    校验 用户名和密码 长度
    """
    username: str = Field(title="username", min_length=1, max_length=6)
    password: str = Field(min_length=1, max_length=6)
    query: QueryModel

    @validator('username')
    def validate_username(cls, value):
        if not (1 <= len(value) <= 6):
            raise ValueError('Username must be between 1 and 6 characters long.')
        return value

    @validator('password')
    def validate_password(cls, value):
        if not (1 <= len(value) <= 6):
            raise ValueError('Password must be between 1 and 6 characters long.')
        return value

    @app.errorhandler(ValidationError)
    def validate_error(e: ValidationError):
        """
        这时候，我们可以通过使用flask的 errorhandler() 装饰函数来注册ValidationError错误，
        异常就可以被validate_error函数捕获，开发者可以给前端直接返回一个友好的错误响应体
        :return: error entry
        """
        return dict(code=-1, msg="请求参数错误", error_info=e.errors()), 400


class UpdatePasswordModel(BaseModel):
    password: str


@app.route("/users/<int(min=1):user_id>", methods=["POST"])
@siwa.doc(query=QueryModel, body=UserModel, resp=UserModel)
def update_password(user_id, body: UserModel):
    """
    example6：路径参数也支持文档化
    """
    print(body.query.gender)
    return {"username": "siwa_pydantic", "id": user_id}


if __name__ == '__main__':
    app.run()
